/*
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/*
 * Changes to this API are expected.
 */

#ifndef _IOKIT_IOHIDLibUserClient_H_
#define _IOKIT_IOHIDLibUserClient_H_

#include "IOHIDKeys.h"

enum IOHIDLibUserClientConnectTypes {
    kIOHIDLibUserClientConnectManager = 0x00484944 /* HID */
};
 
// evil hack alert: we are using type in one of two ways:
// if type == 0, then we want to get the element values
// else type is an object pointer (in kernel space).
// this was deemed better for now than duplicating
// the code from IOUserClient.cpp: is_io_connect_map_memory,
// mapClientMemory and is_io_connect_unmap_memory
enum IOHIDLibUserClientMemoryTypes {
    kIOHIDLibUserClientElementValuesType = 0,
};

// port types: I did consider adding queue ports to this
// as well, but i'm not comfty with sending object pointers
// as a type.
enum IOHIDLibUserClientPortTypes {
    kIOHIDLibUserClientAsyncPortType = 0,
    kIOHIDLibUserClientDeviceValidPortType
};

enum IOHIDLibUserClientCommandCodes {
    kIOHIDLibUserClientDeviceIsValid,
    kIOHIDLibUserClientOpen,
    kIOHIDLibUserClientClose,
    kIOHIDLibUserClientCreateQueue,
    kIOHIDLibUserClientDisposeQueue,
    kIOHIDLibUserClientAddElementToQueue,
    kIOHIDLibUserClientRemoveElementFromQueue,
    kIOHIDLibUserClientQueueHasElement,
    kIOHIDLibUserClientStartQueue,
    kIOHIDLibUserClientStopQueue,
    kIOHIDLibUserClientUpdateElementValues,
    kIOHIDLibUserClientPostElementValues,
    kIOHIDLibUserClientGetReport,
    kIOHIDLibUserClientSetReport,
    kIOHIDLibUserClientGetElementCount,
    kIOHIDLibUserClientGetElements,
    kIOHIDLibUserClientSetQueueAsyncPort,
    kIOHIDLibUserClientNumCommands
};

__BEGIN_DECLS

typedef struct _IOHIDElementValue
{
    IOHIDElementCookie cookie;
    UInt32             totalSize;
    AbsoluteTime       timestamp;
    UInt32             generation;
    UInt32             value[1];
}IOHIDElementValue;

typedef struct _IOHIDReportReq
{
    UInt32      reportType;
    UInt32		reportID;
    void 		*reportBuffer;
    UInt32		reportBufferSize;
}IOHIDReportReq;

struct IOHIDElementStruct;
typedef struct IOHIDElementStruct IOHIDElementStruct;
struct IOHIDElementStruct
{
    UInt32                  cookieMin;
    UInt32                  cookieMax;
    UInt32                  parentCookie;
    UInt32                  type;
    UInt32                  collectionType;
    UInt32                  flags;
    UInt32                  usagePage;
    UInt32                  usageMin;
    UInt32                  usageMax;
    SInt32                  min;
    SInt32                  max;
    SInt32                  scaledMin;
    SInt32                  scaledMax;
    UInt32                  size;
    UInt32                  reportSize;
    UInt32                  reportCount;
    UInt32                  reportID;
    UInt32                  unit;
    UInt32                  unitExponent;
    UInt32                  duplicateValueSize;
    UInt32                  duplicateIndex;
    UInt32                  bytes;
    UInt32                  valueLocation;
    UInt32                  valueSize;
};

enum {
    kHIDElementType			= 0,
    kHIDReportHandlerType
};

__END_DECLS

#if KERNEL

#include <mach/mach_types.h>
#include <IOKit/IOUserClient.h>
#include <IOKit/IOInterruptEventSource.h>

class IOHIDDevice;
class IOHIDEventQueue;
class IOSyncer;
struct IOHIDCompletion;
#if 0
class IOCommandGate;

struct HIDResults;
#endif

enum {
    kHIDQueueStateEnable,
    kHIDQueueStateDisable,
    kHIDQueueStateClear
};

class IOHIDLibUserClient : public IOUserClient 
{
    OSDeclareDefaultStructors(IOHIDLibUserClient)
    
    bool resourceNotification(void *refCon, IOService *service);
    void resourceNotificationGated();
    
    void setStateForQueues(UInt32 state, IOOptionBits options = 0);
    
    void setValid(bool state);
    
    IOReturn dispatchMessage(void* message);
    
protected:
    static const IOExternalMethodDispatch
		sMethods[kIOHIDLibUserClientNumCommands];

    IOHIDDevice *fNub;
    IOWorkLoop *fWL;
    IOCommandGate *fGate;
    IOInterruptEventSource * fResourceES;
    
    OSSet * fQueueSet;

    UInt32 fPid;
    task_t fClient;
    mach_port_t fWakePort;
    mach_port_t fValidPort;
    
    void * fValidMessage;
    
    bool fNubIsTerminated;
	bool fNubIsKeyboard;
    
    IOOptionBits fCachedOptionBits;
        
    IONotifier * fResourceNotification;
    
    UInt64 fCachedConsoleUsersSeed;
    
    bool    fValid;
    uint64_t fGeneration;
    // Methods
    virtual bool initWithTask(task_t owningTask, void *security_id, UInt32 type);
    
    virtual IOReturn clientClose(void);

    virtual bool start(IOService *provider);

    virtual bool didTerminate(IOService *provider, IOOptionBits options, bool *defer);
        
    virtual void free();

    virtual void cleanupGated();
    
    virtual IOReturn message(UInt32 type, IOService * provider, void * argument = 0 );
    virtual IOReturn messageGated(UInt32 type, IOService * provider, void * argument = 0 );

    virtual IOReturn registerNotificationPort(mach_port_t port, UInt32 type, UInt32 refCon );
    virtual IOReturn registerNotificationPortGated(mach_port_t port, UInt32 type, UInt32 refCon );

    // return the shared memory for type (called indirectly)
    virtual IOReturn clientMemoryForType(
                           UInt32                type,
                           IOOptionBits *        options,
                           IOMemoryDescriptor ** memory );
    IOReturn clientMemoryForTypeGated(
                           UInt32                type,
                           IOOptionBits *        options,
                           IOMemoryDescriptor ** memory );
						   
	IOReturn externalMethod(	uint32_t                    selector, 
                                IOExternalMethodArguments * arguments,
                                IOExternalMethodDispatch *  dispatch, 
                                OSObject *                  target, 
                                void *                      reference);

    IOReturn externalMethodGated(void * args);


    // Open the IOHIDDevice
    static IOReturn _open(IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        open(IOOptionBits options);

    // Close the IOHIDDevice
    static IOReturn _close(IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        close();
                   
    // Get Element Counts
    static IOReturn _getElementCount(IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);    
    IOReturn        getElementCount(uint64_t * outElementCount, uint64_t * outReportElementCount);

    // Get Elements
    static IOReturn _getElements(IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);    
    IOReturn        getElements(uint32_t elementType, void *elementBuffer, uint32_t *elementBufferSize);
    IOReturn        getElements(uint32_t elementType, IOMemoryDescriptor * mem,  uint32_t *elementBufferSize);

    // Device Valid
    static IOReturn _deviceIsValid(IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);    
    IOReturn        deviceIsValid(bool *status, uint64_t *generation);
    
    // Set queue port
    static IOReturn _setQueueAsyncPort(IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        setQueueAsyncPort(IOHIDEventQueue * queue, mach_port_t port);

    // Create a queue
    static IOReturn _createQueue(IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        createQueue(uint32_t flags, uint32_t depth, uint64_t * outQueue);

    // Dispose a queue
    static IOReturn _disposeQueue(IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        disposeQueue(IOHIDEventQueue * queue);

    // Add an element to a queue
    static IOReturn _addElementToQueue(IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        addElementToQueue(IOHIDEventQueue * queue, IOHIDElementCookie elementCookie, uint32_t flags, uint64_t *pSizeChange);
   
    // remove an element from a queue
    static IOReturn _removeElementFromQueue (IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        removeElementFromQueue (IOHIDEventQueue * queue, IOHIDElementCookie elementCookie, uint64_t *pSizeChange);
    
    // Check to see if a queue has an element
    static IOReturn _queueHasElement (IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        queueHasElement (IOHIDEventQueue * queue, IOHIDElementCookie elementCookie, uint64_t * pHasElement);
    
    // start a queue
    static IOReturn _startQueue (IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        startQueue (IOHIDEventQueue * queue);
    
    // stop a queue
    static IOReturn _stopQueue (IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        stopQueue (IOHIDEventQueue * queue);
                            
    // Update Feature element value
    static IOReturn	_updateElementValues (IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        updateElementValues (const uint64_t * lCookies, uint32_t cookieCount);
                                                
    // Post element value
    static IOReturn _postElementValues (IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        postElementValues (const uint64_t * lCookies, uint32_t cookieCount);
                                                
    // Get report
    static IOReturn _getReport(IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        getReport(void *reportBuffer, uint32_t *pOutsize, IOHIDReportType reportType, uint32_t reportID, uint32_t timeout = 0, IOHIDCompletion * completion = 0);
    IOReturn        getReport(IOMemoryDescriptor * mem, uint32_t * pOutsize, IOHIDReportType reportType, uint32_t reportID, uint32_t timeout = 0, IOHIDCompletion * completion = 0); 

    // Set report
    static IOReturn _setReport(IOHIDLibUserClient * target, void * reference, IOExternalMethodArguments * arguments);
    IOReturn        setReport(const void *reportBuffer, uint32_t reportBufferSize, IOHIDReportType reportType, uint32_t reportID, uint32_t timeout = 0, IOHIDCompletion * completion = 0);
    IOReturn        setReport(IOMemoryDescriptor * mem, IOHIDReportType reportType, uint32_t reportID, uint32_t timeout = 0, IOHIDCompletion * completion = 0);

    void ReqComplete(void *param, IOReturn status, UInt32 remaining);
    IOReturn ReqCompleteGated(void *param, IOReturn status, UInt32 remaining);
};

#endif /* KERNEL */

#endif /* ! _IOKIT_IOHIDLibUserClient_H_ */

